package jwf.fcgi;

import java.io.IOException;
import java.io.InputStream;

public class FCGXInputStream extends InputStream {

    private static final int DEFAULT_BUFFER_LEN = 40960;

    private static final int MASK = 0xFF;
    private static final int EOF = -1;

    private InputStream in;

    private int buflen;
    private byte[] buffer;
    private int current;
    private int stop;

    private boolean isClosed;

    public FCGXInputStream(InputStream in) {
	this.in = in;
	buflen = DEFAULT_BUFFER_LEN;
	buffer = new byte[buflen];
	current = stop = 0;
	try {
	    fill();
	} catch (Exception e) {
	    e.printStackTrace();
	}
    }

    @Override
    public int read() throws IOException {
	if (current != stop) {
	    return buffer[current++] & MASK;
	}
	if (isClosed) {
	    return EOF;
	}
	fill();
	if (current != stop) {
	    return buffer[current++] & MASK;
	}
	return EOF;
    }

    public int read(byte b[]) throws IOException {
	return read(b, 0, b.length);
    }

    public int read(byte b[], int offset, int len) throws IOException {
	if (len <= 0) {
	    return EOF;
	}
	if (offset < 0) {
	    return EOF;
	}

	if (len <= (stop - current)) {
	    System.arraycopy(buffer, current, b, offset, len);
	    current += len;
	    return len;
	}

	int move = 0;
	while (true) {
	    if (current != stop) {
		int min = Math.min(len - move, stop - current);
		System.arraycopy(buffer, current, b, offset, min);
		current += min;
		move += min;
		if (move == len) {
		    return move;
		}
		offset += min;
	    }
	    if (isClosed) {
		return move;
	    }
	    fill();
	}
    }

    @Override
    public int available() throws IOException {
	return stop - current + in.available();
    }

    private void fill() throws IOException {
	if (current == stop) {
	    int count = 0;
	    try {
		count = in.read(buffer, 0, buflen);
	    } catch (Exception e) {
		e.printStackTrace();
		isClosed = true;
	    }
	    if (count != EOF) {
		current = 0;
		stop = count;
	    } else {
		isClosed = true;
	    }
	}
    }

    public String toString() {
	StringBuffer sb = new StringBuffer();
	sb.append("current:").append(current).append("\t");
	sb.append("stop:").append(stop).append("\t");
	return sb.toString();
    }

    /**
     * Read a FCGI Header
     * 
     * @param headerBuffer
     * @return
     * @throws IOException
     */
    public int readHeader(byte[] headerBuffer) throws IOException {
	return read(headerBuffer, 0, headerBuffer.length);
    }

}
